<?php
/* 
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
*/

/**
 * Helper_JDatePagination производит всякий разный html для класса JDatePagination
 *
 * @author chaporgin_a
 */
class VA_Helper_JDatePagination {
    /**
     * Для того, чтобы слева и справа от выбранных элементов в ленте были еще и невыбранные
     *
     * Чтобы пользователь мог перейти на какие-нибудь еще невыбранные элементы ленты
     * Т.к. лента вообщем бесконечна, нужно показывать что-то слева и справа от выбранных элементов
     * @var int
     */
    public $defaultOffsetInRibbon = 1;
    protected $activeElementMark = 'active';
    protected $hasMaterialElementMark = 'hasMaterial';
    protected $noMaterialElementMark = 'noMaterial';
    /**
     * Иногда бывает, что из ленты прыгаешь в очень широкий диапазон, например, в год,
     * нужно резко сократить диапазон до месяца
     * Диапазоны всех ссылок будут формировать длиной в эту переменную
     * @var string из множества month, year, day
     */
    protected $defaultRange = 'months';

    /**
     * Если установить опцию cautious в FALSE (по умолч), то при формировании ссылок не будем пытаться прописать полную ссылку, иначе нам пригодится эта опция
     * @var int
     */
    protected $categoryId = null;
    protected $fullLinks = FALSE;
    /**
     * Устанавливает айди категории
     * @param int $id
     * @return VA_Helper_JDatePagination
     */
    public function setCategoryId($id) {
        $this->categoryId = $id;
        return $this;
    }
    /**
     *
     * @var VA_JDatePagination
     */
    protected $paginator = null;
    protected $startDate = null;
    protected $endDate = null;
    public function setPaginator(VA_JDatePagination $paginator) {
        $this->paginator = $paginator;
        return $this;
    }
    static public function GetOption($name, $options, $default = null) {
        if(!key_exists($name, $options) && (null === $default))
            throw new Exception(sprintf('required option "%s" is missing!', $name));
        if(key_exists($name, $options)) return $options[$name];
        else return $default;
    }
    /**
     * Возвращает сложный массив дат которые надо вывести на печать
     *
     * @param array $options
     * @return array
     */
    public function RibbonAsArray($options = array()) {
        $offsetUnit = self::GetOption('step', $options, 'months');
        $elementsBeforeRange = self::GetOption('before', $options, $this->defaultOffsetInRibbon);
        $elementsAfterRange = self::GetOption('after', $options, $this->defaultOffsetInRibbon);
        $defaultRange = self::GetOption('selectrange', $options, $this->defaultRange);
        $this->fullLinks = self::GetOption('cautious', $options, FALSE);
        $format = $this->getFormat($offsetUnit);
        return $this->paginator->prepareStopDates($offsetUnit, strtotime(date($format, $this->paginator->getFromTimestamp())), $elementsBeforeRange, $elementsAfterRange);
    }
    /**
     * Возвращает строку для функций типа date() чтобы установить формат дат в URL
     *
     * @param string $offsetUnit
     * @return string
     */
    protected function getFormat($offsetUnit) {
        switch($offsetUnit) {
            case 'years':
                return 'Y-01-01';
                break;
            case 'days':
                return 'Y-m-d';
                break;
            default:
                return 'Y-m-01';
        }
    }
    /**
     * Отрисовывает ленту c временными промежутками
     * @param array $options step из множества (months, days, years)
     * @return string
     */
    public function Ribbon($options = array()) {
        $offsetUnit = self::GetOption('step', $options, 'months');
        $defaultRange = self::GetOption('selectrange', $options, $this->defaultRange);
        $stopDates = $this->RibbonAsArray($options);
        $format = $this->getFormat($offsetUnit);

        $return = '';
        $list = array();
        $i=0;
        $count = count($stopDates);
        foreach ($stopDates as $date) {
            $isActive = (($this->paginator->getFromTimestamp() <= $date) && ($date < $this->paginator->getTillTimestamp()) );

            $rangeStart = strtotime(date($format, $date));
            $rangeEnd = strtotime(sprintf('+1 %s', $offsetUnit), $rangeStart);

            //if($omitEmpty && (0 == count($this->paginator->findElementsInRange($rangeStart, $rangeEnd))))
            //    continue;
            $months = array('январь', 'февраль', 'март', 'апрель', 'май', 'июнь', 'июль', 'август', 'сентябрь', 'октябрь', 'ноябрь', 'декабрь');

            switch($offsetUnit) {
                case 'years':
                    $name = date('Y', $rangeStart);
                    break;
                case 'days':
                    $name = date('l', $rangeStart);
                    break;
                default:

                    $name = $months[date('m',$rangeStart)-1].' '.date('Y', $rangeStart);
            }
            $hasMaterial = $this->paginator->hasMaterialInRange($rangeStart,$rangeEnd);
            $class = array();
            if(++$i === $count) {
                $class[] = 'last_child';
                if(!$hasMaterial) $class[] = 'last'.$this->noMaterialElementMark;
            } elseif(1 === $i) {
                if(!$hasMaterial) $class[] = 'first'.$this->noMaterialElementMark;
            }

            $list[] = $this->printElementOfRibbon(
                    array($rangeStart,$rangeEnd),
                    $this->prepareLinkRange($rangeStart,$rangeEnd, $defaultRange),
                    $name,
                    $isActive,
                    $hasMaterial,
                    $class
            );
        }
        $return = $this->wrapList($list,array('ribbon_'.$offsetUnit));
        return $return;
    }
    protected function prepareLinkRange($rangeStart, $rangeEnd, $step) {
        switch($step) {
            case 'years':
                $format = 'Y-01-01';
                break;
            case 'months':
                $format = 'Y-m-01';
                break;
            default:
                $format = 'Y-m-d';
                break;
        }
        $element = $this->paginator->findElementsInRange($rangeStart,$rangeEnd);
        if( 0 === count($element)) $linkRangeStart = date($format, $rangeStart);
        else $linkRangeStart = date($format, strtotime($element[0]->created));
        $linkRangeEnd = date($format, strtotime('+1 '.$step, strtotime($linkRangeStart)));
        return array($linkRangeStart, $linkRangeEnd);
    }
    /**
     * Дополнительная отрисовка списка месяцев перед отправкой клиенту
     *
     * Функция проверяет, нет ли в пространстве имен функции с именем paginator_print_element
     * и если есть, неренаправляет всю работу ей
     * @param string $list html со материалами
     * @param array $class классы которыми пометить контейнер
     * @return <type>
     */
    protected function wrapList($list, $class) {
        if( function_exists('paginator_wrap_list')) return paginator_wrap_list($list, $class);
        $return = '';
        foreach($list as $element) $return .= $element;
        $class[] = 'ribbon';
        $return = '<ul class="'.join(' ',$class).'">'.$return.'</ul>';
        return $return;
    }
    /**
     * Напечатать дату как элемент ленты месяцев
     *
     * Функция проверяет, нет ли в пространстве имен функции с именем paginator_print_element
     * и если есть, неренаправляет всю работу ей
     * @param array $range (timestamp, timestamp) - начало и конец периода, за который отвечает этот элемент
     * @param array $linkRange (timestamp, timestamp) - начало и конец периода, в который мы предлагаем пользователю попасть по ссылке
     * @param string $nameOfLink текст ссылки
     * @param bool $isActive пометить ли ссылку, как выбранную в данный момент
     * @param bool $hasMaterial TRUE, если после перехода по ссылке пользователь обнаружит там материалы
     * @param array $class массив из названий css классов
     * @return string
     */
    protected function printElementOfRibbon($range, $linkRange, $nameOfLink, $isActive = FALSE, $hasMaterial = FALSE, $class = array()) {
        if( function_exists('paginator_print_element')) return paginator_print_element($range, $linkRange, $nameOfLink, $isActive, $hasMaterial);
        //TODO: учесть что в шаблонах можно перегружать эту функцию
        list($startDate,$endDate) = $range;
        if($isActive || !$hasMaterial) $element = "<span>$nameOfLink</span>";
        else {
            $route = "&limit=1000&from=".$linkRange[0]."&till=".$linkRange[1];
            if($this->fullLinks) {
                $route.="&view=category&layout=dateblog";
                if(null !== $this->categoryId) $route .= "&id=$this->categoryId";
            }
            $element = sprintf('<a href="%s">%s</a>'
                    , JRoute::_($route)
                    , $nameOfLink
            );
        }
//        $class[] = 'page';
        if($isActive) $class[] = $this->activeElementMark;
        if($hasMaterial) $class[] = $this->hasMaterialElementMark;
        else $class[] = $this->noMaterialElementMark;
        return sprintf('<li class="%s">%s</li>'
                , join(' ', $class)
                , $element
        );
    }
    public function printPreviosMonth() {
        return $this->printMonthArrow(VA_JDatePagination::DIR_DESC);
    }
    public function printNextMonth() {
        return $this->printMonthArrow(VA_JDatePagination::DIR_ASC);
    }
    protected function printMonthArrow($direction) {
        $date = $this->paginator->getFirstDateAfterActiveRegion($direction);
        $arrowText = VA_JDatePagination::DIR_ASC === $direction?'&rarr;':'&larr;';
        if(null === $date) return;
        else {
            $start = date('Y-m-01', $date);
            $end = date('Y-m-01', strtotime('+1 month', strtotime($start)));
            return sprintf('<span class="arrow"><a href="%s">%s</a></span>'
                    ,  JRoute::_("&limit=1000&from=".$start."&till=".$end)
                    , $arrowText
            );
        }
    }
}

